Repository navigation
fix(error-tracking): stop exception card header label overlapping the tabs - #88176
Conversation
… tabs The header's label cell carried `min-w-0` with nothing clipping it, so once its grid track collapsed the "Exception" label painted straight over the tab bar instead of disappearing. The symmetric `1fr auto 1fr` template brought that on early: it reserves two equal gutters to centre the tab bar even though only one gutter has content. Clip the label cell, and degrade the header on the card's own width — a container query, since the card lives in a resizable split pane where viewport breakpoints say nothing useful. Below @XL the label drops to sr-only and the tab bar takes the slack; at @XL and up the symmetric gutters and centred tab bar come back. The action cell sits in an `auto` track so it never shrinks, and the tab bar scrolls (justify-start, so a centred overflow can't put the first tab out of reach) as a last valve. Adds ExceptionCardHeaderWidths and ExceptionCardHeaderWidthsWithAction stories pinning each branch, the second with the right-hand action occupied.
|
😎 Merged successfully - details. |
🤖 CI report✅ Trunk lane — non-backend laneThis PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.
|
| File | Size | Δ vs base |
|---|---|---|
render-query/src/render-query/render-query.js |
21.64 MiB | 🟢 -291.5 KiB (-1.3%) |
posthog-app/src/sharedChunkAnchors.js |
247.2 KiB | 🔺 +245.7 KiB (+16619.6%) |
exporter/src/exporterSharedChunkAnchors.js |
247.0 KiB | 🔺 +245.7 KiB (+18777.3%) |
posthog-app/src/lib/components/Shortcuts/utils/DebugCHQueriesImpl.js |
14.9 KiB | 🟢 -18.5 KiB (-55.3%) |
posthog-app/_parent/products/stamphog/frontend/scenes/StamphogDigestsScene/StamphogDigestsScene.js |
7.2 KiB | 🟢 -1.2 KiB (-14.3%) |
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.36 MiB · 22 files | 🔺 +718 B (+0.1%) | ███░░░░░░░ 30.2% of 4.51 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.76 MiB · 3,235 files | 🔺 +102 B (+0.0%) | █████████░ 90.2% of 9.71 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 304.9 KiB | ../node_modules/.pnpm/posthog-js@1.418.16/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 258.5 KiB | ../node_modules/.pnpm/posthog-js@1.418.16/node_modules/posthog-js/dist/module.js |
| 246.0 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 154.2 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 104.6 KiB | src/lib/api.ts |
| 95.1 KiB | ../packages/quill/packages/quill/dist/index.js |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 90.6 KiB | ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Toolbar bundle — eager 2.25 MiB within budget
What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.
| Metric | Size | Δ vs base | Budget |
|---|---|---|---|
| Eager (shipped) entry + static imports |
2.25 MiB · 17 files | 🔺 +830 B (+0.0%) | ████░░░░░░ 39.3% of 5.72 MiB |
| Deferred (lazy) | 2.09 MiB · 33 files | 🟢 -950 B (-0.0%) | n/a — loads on demand |
Loader dist/toolbar.js |
1.1 KiB | no change | █░░░░░░░░░ 5.8% of 19.5 KiB |
Largest eagerly-shipped chunks
| Size | File |
|---|---|
| 745.2 KiB | dist/toolbar/toolbar-app-BJUP7HKG.css |
| 582.9 KiB | dist/toolbar/chunk-chunk-FNIJRHDL.js |
| 484.6 KiB | dist/toolbar/chunk-chunk-GTGJDCUD.js |
| 133.8 KiB | dist/toolbar/chunk-chunk-TUAYUMDK.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-T5KY5WYR.js |
| 71.2 KiB | dist/toolbar/toolbar-app-KEMKGXST.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-27JL52RE.js |
| 35.6 KiB | dist/toolbar/chunk-chunk-LAHTWA76.js |
| 20.9 KiB | dist/toolbar/chunk-chunk-ZY7FI6JJ.js |
| 12.2 KiB | dist/toolbar/chunk-chunk-PIK3PADE.js |
Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile
✅ Dist folder size — 🟢 -1.86 MiB (-0.1%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1462.74 MiB · 🟢 -1.86 MiB (-0.1%)
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
|
Reviews (1): Last reviewed commit: "fix(error-tracking): stop exception card..." | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b3f6159281
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
✅ Visual changes approved by @cat-ph — baseline updated in 4 changed, 4 new. Changed New |
Three fixes from review on the header layout change. Inline-size containment makes an element's width independent of its contents, so it contributes nothing to a shrink-to-fit ancestor. With the container on the Tabs root that covered the whole card, which collapsed it to zero wherever its width came from its content — visual review caught this on `exception-card-with-footer`, rendering at 32px instead of 570px. The container now wraps the header alone, so the card is still sized by its body. That story also gains a definite width, like its siblings: `w-full` resolves against a shrink-to-fit storybook wrapper, so the card was sizing to its own content rather than to the story. Base UI scrolls the active tab into view on mount and on keyboard navigation, but not when the value changes from elsewhere. The timeline switches to the recording tab on a timestamp click, which in a narrow pane left the active tab outside the scroller with no scrollbar to reveal it. Nudging scrollLeft rather than calling scrollIntoView keeps ancestors where they are. Comments no longer narrate what the layout used to do, per the AGENTS.md rule against change history in source; that belongs in the commit and the PR.
8 updated Run: 020d378b-5f94-4ae4-969a-912843ab9563 Co-authored-by: cat-ph <268578347+cat-ph@users.noreply.github.com>
Problem
Anyone opening an exception in a narrow pane — a split view, or a phone — saw the exception card header render
ExStackpTrace: the "Exception" label painted on top of the tab bar instead of getting out of its way.Three things combine in that one 40px row:
min-w-0, which lets its grid track collapse below the label's width, but nothing clipped the overflow — so the text spilled over its neighbour rather than disappearing1fr auto 1frtemplate reserves two equal gutters to centre the tab bar, so the header needs2 x label + tabsof width before anything fits, even though only one gutter has content — which reaches the collapsing regime earlyw-fit+whitespace-nowrapin anautotrack, so under ~390px it overflows the header with nothing catching itChanges
The header now degrades on a priority order — the action never goes, the tab bar next, the label first — keyed to the card's own width through a container query rather than the viewport, because the card lives in a resizable split pane.
sr-only, so it stays in the accessibility treeautotrack: never shrinks, never clippedoverflow-hiddenon the label cell is the actual overlap fix; the rest is what keeps the clip from being the first thing a person notices. The tab bar also picks upjustify-start, overriding the list's ownjustify-center— a centred flex row that overflows spills off both edges, which would leave the first tab out of reach of the scroller.Screenshots
Every shot is the new
ExceptionCardHeaderWidthsstory, one card per width, rendered in Storybook.Before — the overlap reproduces at 300px (
ExStackpTrace) and 420px (ExceptStack Trace), and is absent from 560px up, which is why it only shows in a narrow pane:After — the label gives way to the logomark below 576px and the tab bar takes the slack, scrolling at 300px:
After, with the right-hand cell occupied (
ExceptionCardHeaderWidthsWithAction) — the tightest the tab bar ever gets, and View logs stays whole at every width:How did you test this code?
ExceptionCardHeaderWidthsandExceptionCardHeaderWidthsWithActionpin each branch of the container query at 300 / 420 / 560 / 576 / 900px, the second with the right-hand action occupied so the tab bar has the least room it ever gets. Both are untagged, so visual review snapshots them. The regression they catch is the overlap itself, which no jsdom test can see — it is purely a layout outcome.Verified by rendering those same stories against the pre-fix component: the overlap reproduces at 300px and 420px, and is gone after.
Automated checks run locally, all clean:
oxfmt --check,oxlint,tsgo --noEmit. No manual testing in the running app.Expected visual review diff
exception-card-with-footerchanges on purpose. It rendered at an accidental width —w-fullresolves against a shrink-to-fit storybook wrapper, so the card sized to its own content — and it now has a definitew-[1000px]like the other card stories.Worth knowing for anyone reusing the container-query pattern:
container-type: inline-sizemakes an element's width independent of its contents, so it contributes nothing to a shrink-to-fit ancestor. Putting it on the whole card collapsed that story to 32px. The container wraps the header alone for that reason.Automatic notifications
Docs update
None — no user-facing behaviour beyond the layout itself.
Agent context
Autonomy: Human-driven (agent-assisted)
Authored with Claude Code (Opus 5). Skills invoked:
/pr-closeoutand/autoreview, the latter running Codex against the branch diff — it returned clean with no actionable findings.Two decisions changed across the session, both caught by screenshotting the stories rather than by reading the CSS. The breakpoint started at
@lg(512px), where the label reappears but immediately truncates toExce..., since symmetric gutters leave only ~78px a side at that width; it moved to@xl(576px), where the full label fits. The centred-overflow clipping in the tab bar surfaced the same way.